Skip to content

Warn when the installation ID can't be saved; add requirePersisted - #10

Merged
catsika merged 1 commit into
mainfrom
fix/installation-id-not-saved
Nov 13, 2026
Merged

catsika merged 1 commit into
mainfrom
fix/installation-id-not-saved

Conversation

@catsika

@catsika catsika commented Nov 12, 2026

Copy link
Copy Markdown
Member

Problem

KeyMint.getOrCreateInstallationId() swallowed write errors and returned an unsaved ID. On a read-only disk, in a sandbox, or without permission to write ~/.keymint, every launch generated a different ID, so the same machine used another activation slot each time, and the app got no signal.

Change (backwards compatible)

  • Default unchanged. The method still returns an ID and never throws because of a failed save. It now emits one KeymintInstallationIdWarning per process via process.emitWarning (code KEYMINT_INSTALLATION_ID_NOT_SAVED), naming the storage path.

  • Opt-in strict mode. New InstallationIdOptions { requirePersisted?: boolean }, default false. Either form works:

    • getOrCreateInstallationId(storagePath, { requirePersisted: true })
    • getOrCreateInstallationId({ storagePath, requirePersisted: true })

    With true it throws the new exported InstallationIdError (name, path, cause) when the ID can't be saved and read back, or an existing file can't be read.

  • After writing, the value is read back to confirm it persisted.

  • Return type unchanged (string).

  • The storage directory now uses path.dirname instead of splitting on /, so Windows paths are created correctly.

  • JSDoc, README ("When the installation ID can't be saved") and CHANGELOG (Unreleased) describe the default, the warning and the strict option, and recommend requirePersisted: true for desktop apps that activate devices.

No version bump.

Tests

New tests/identity.test.cjs (added to npm test):

  • saves normally and returns the same ID next time (both call forms);
  • an existing readable file is reused;
  • unwritable path in default mode returns an ID and warns exactly once;
  • strict mode throws InstallationIdError with the path, and doesn't warn;
  • read-only directory via chmod (skipped on Windows or as root);
  • strict mode throws when the value doesn't read back.

New tests/types/identity.check.ts checks the overloads and that the return type is still string.

npm run lint: clean. npm test: 64 passed (live tests not run).

…irePersisted

getOrCreateInstallationId swallowed write errors and returned an unsaved
ID, so every launch on a read-only or sandboxed disk produced a new ID and
used another activation slot, with no signal to the app.

- Default behaviour is unchanged: an unsaved ID is still returned, but one
  KeymintInstallationIdWarning (code KEYMINT_INSTALLATION_ID_NOT_SAVED) is
  now emitted per process via process.emitWarning.
- New opt-in { requirePersisted: true } (second argument, or a single
  options object with storagePath) throws InstallationIdError with the
  storage path when the ID can't be saved and read back, or an existing
  file can't be read.
- The saved value is read back to confirm it persisted.
- Use path.dirname for the storage directory (Windows paths).
- Tests, type checks, README and CHANGELOG.
@catsika
catsika merged commit b0320da into main Nov 13, 2026
3 checks passed
@catsika
catsika deleted the fix/installation-id-not-saved branch November 13, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant